// Copyright(c) 2011 Matthew McMullan, Jorel Lalicki and Mike Heise, Jorel Lalicki and Mike Heise. See copying.txt for details.

#ifndef __agml_mbulkstack_h__
#define __agml_mbulkstack_h__

// make sure that this file is never included directly
#ifndef __agml_agml_h__
#error "Include AGML from agml.h only. This file is not a valid entry point for the library."
#endif

namespace agml {
	namespace matrix_stack_helpers {
		template<typename t, u32 width, u32 height> struct mbulkstack_plate {
			union {
				_v128 holder;
				struct {
					mbulkstack_plate *next;
					mbulkstack_plate *previous;
				};
			};
			mbulk<t,width,height> matrix;
		};
	}
	template<typename t, u32 width, u32 height> class mbulkstack {
	protected:
		typedef matrix_stack_helpers::mbulkstack_plate<t,width,height> plate;
		typedef mbulk<t,width,height> mtype;
		plate root;
		plate *_top;
		u32_fast depth;
	public:
		mbulkstack() {
			root.next = 0;
			root.previous = 0;
			_top = &root;
			depth = 0;
		}
		mbulkstack(const mtype &m) {
			root.next = 0;
			root.previous = 0;
			_top = &root;
			root.matrix = m;
			depth = 0;
		}
		~mbulkstack() {
			while (_top->next !=0) {
				_top = _top->next;
			}
			while (_top->previous != 0) {
				_top = _top->previous;
				chunk_allocator.free(_top->next);
			}
		}
		u32_fast size() const {
			return depth;
		}
		const mtype &top() const {
			return _top->matrix;
		}
		mtype &top() {
			return _top->matrix;
		}
		const mtype &operator*() const {
			return _top->matrix;
		}
		mtype &operator*() {
			return _top->matrix;
		}
		mtype &push() {
			if (_top->next == 0) {
				chunk_allocator.alloc(_top->next);
				_top->next->previous = _top;
				_top->next->next = 0;
			}
			_top->next->matrix = _top->matrix;
			_top = _top->next;
			depth++;
			return _top->matrix;
		}
		mtype &pop() {
			if (_top->previous!=0) {
				_top = _top->previous;
				depth--;
			}
			return _top->next->matrix;
		}
	};
}

#endif
